﻿//
// Created by 25007 on 2022/10/21.
//
#include "gtest/gtest.h"
#include <string>
#include <iostream>
#include <vector>
#include <forward_list>
#include <list>
#include <queue>
#include <unordered_map>
#include <unordered_set>

#include <range/v3/view/filter.hpp>
#include <range/v3/view/iota.hpp>
#include <range/v3/view/transform.hpp>
#include "log.h"

// get everything
#include <range/v3/all.hpp>

// 排序
#include <range/v3/action/sort.hpp>

// 去重
#include <range/v3/action/unique.hpp>

// specific includes
#include <range/v3/algorithm/is_sorted.hpp>

//pprint
#include <pprint.hpp>

#include "fmt/core.h"

// 过滤
TEST(rang_v3, filter) {
  // #include <range/v3/view/filter.hpp>
  std::vector<int> numbers{1, 2, 3, 4};

  auto even = numbers
	  // Keep only the even numbers
	  | ranges::views::filter([](const int &num) {
		return num % 2 == 0;
	  });
  //LOG_INFO << even;
  //std::cout << even << '\n';
}

// 生成 3 -6之间的数
TEST(rang_v3, ints) {

  // #include <range/v3/view/iota.hpp>

  auto numbers = ranges::views::ints(3, 7);

  std::cout << numbers << '\n';

}

TEST(rang_v3, transform) {


  // #include <range/v3/view/transform.hpp>
  std::vector<int> numbers{1, 2, 3};

  auto halved = numbers
	  // Divide each integer by 2, converting it into a double
	  | ranges::views::transform([](const int &num) {
		return num / 2.0;
	  });

  std::cout << halved << '\n';
}

TEST(rang_v3, hello) {

// #include <range/v3/all.hpp>
  std::string s{"hello"};

  // 链式结构打印

  auto print = [](int i) { std::cout << i << ' '; };

  // output: h e l l o
  ranges::for_each(s, [](char c) { std::cout << c << ' '; });
  std::cout << '\n';

  std::cout << "vector:   ";
  std::vector<int> v{1, 2, 3, 4, 5, 6};
  ranges::for_each(v, print); // 1 2 3 4 5 6

  std::cout << "\narray:    ";
  std::array<int, 6> a{1, 2, 3, 4, 5, 6};
  ranges::for_each(a, print);

  std::cout << "\nlist:     ";
  std::list<int> ll{1, 2, 3, 4, 5, 6};
  ranges::for_each(ll, print);

  std::cout << "\nfwd_list: ";
  std::forward_list<int> fl{1, 2, 3, 4, 5, 6};
  ranges::for_each(fl, print);

  std::cout << "\ndeque:    ";
  std::deque<int> d{1, 2, 3, 4, 5, 6};
  ranges::for_each(d, print);
  std::cout << '\n';


  // map类型打印
  auto printm = [](const std::pair<std::string, int>& p) {
	std::cout << p.first << ":" << p.second << ' ';
  };

  std::cout << "set:           ";
  std::set<int> si{1, 2, 3, 4, 5, 6};
  ranges::for_each(si, print);

  std::cout << "\nmap:           ";
  std::map<std::string, int> msi{{"one", 1}, {"two", 2}, {"three", 3}};
  ranges::for_each(msi, printm);

  std::cout << "\nunordered map: ";
  std::unordered_map<std::string, int> umsi{{"one", 1}, {"two", 2}, {"three", 3}};
  ranges::for_each(umsi, printm);

  std::cout << "\nunordered set: ";
  std::unordered_set<int> usi{1, 2, 3, 4, 5, 6};
  ranges::for_each(usi, print);
  std::cout << '\n';
}

// 排序去重
TEST(rang_v3, sort_unique) {
  std::vector<int> vi{9, 4, 5, 2, 9, 1, 0, 2, 6, 7, 4, 5, 6, 5, 9, 2, 7,
					  1, 4, 5, 3, 8, 5, 0, 2, 9, 3, 7, 5, 7, 5, 5, 6, 1,
					  4, 3, 1, 8, 4, 0, 7, 8, 8, 2, 6, 5, 3, 4, 5};
  using namespace ranges;
  vi |= actions::sort | actions::unique;
  // prints: [0,1,2,3,4,5,6,7,8,9]
  std::cout << views::all(vi) << '\n';
}

// 是否是有序的
TEST(rang_v3, is_sorted) {
  // 让输出流将bool解析成为true或者 false
  std::cout << std::boolalpha;

  std::vector<int> v{1, 2, 3, 4, 5, 6};
  std::cout << "vector:   " << ranges::is_sorted(v) << '\n';

  std::array<int, 6> a{6, 2, 3, 4, 5, 6};
  std::cout << "array:    " << ranges::is_sorted(a) << '\n';
}

// 查找
TEST(rang_v3, find) {

  auto is_six = [](int i) -> bool { return i == 6; };

  std::cout << "vector:   ";

  std::vector<int> v{6, 2, 6, 4, 6, 1};
  {
	auto i = ranges::find(v, 6); // 1 2 3 4 5 6
	std::cout << "*i: " << *i << '\n';
  }
  {
	auto i = ranges::find(v, 10); // 1 2 3 4 5 6
	if (i == ranges::end(v)) {
	  std::cout << "didn't find 10\n";
	}
  }
  {
	auto i = ranges::find_if(v, is_six);
	if (i != ranges::end(v)) {
	  std::cout << "*i: " << *i << '\n';
	}
  }
  {
	auto i = ranges::find_if_not(v, is_six);
	if (i != ranges::end(v)) {
	  std::cout << "*i: " << *i << '\n';
	}
  }
  {
	auto i = ranges::find(v, 6);
	i++;
	if (i != ranges::end(v)) {
	  std::cout << "*i after ++ (2 expected): " << *i;
	}
  }

  std::cout << "\narray:    ";

  std::array<int, 6> a{6, 2, 3, 4, 5, 1};
  {
	auto i = ranges::find(a, 6);
	if (i != ranges::end(a)) {
	  std::cout << "*i: " << *i;
	}
  }
  std::cout << "\nlist:     ";

  std::list<int> li{6, 2, 3, 4, 5, 1};
  {
	auto i = ranges::find(li, 6);
	if (i != ranges::end(li)) {
	  std::cout << "*i: " << *i;
	}
  }

  std::cout << "\nfwd_list: ";

  std::forward_list<int> fl{6, 2, 3, 4, 5, 1};
  {
	auto i = ranges::find(fl, 4);
	if (i != ranges::end(fl)) {
	  std::cout << "*i: " << *i;
	}
  }
  std::cout << "\ndeque:    ";

  std::deque<int> d{6, 2, 3, 4, 5, 1};
  {
	auto i = ranges::find(d, 6);
	if (i != ranges::end(d)) {
	  std:: cout << "*i: " << *i;
	}
  }
  std::cout << '\n';
}

// 过滤 遍历 转换
TEST(rang_v3, filter_transform) {
  std::vector<int> const vi{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  using namespace ranges;
  auto rng = vi | views::filter([](int i) { return i % 2 == 0; }) |
	  views::transform([](int i) { return std::to_string(i); });
  // prints: [2,4,6,8,10]
  std::cout << rng << '\n';
}

// 计算 6出现的次数
TEST(rang_v3, count_if) {
  // #include <range/v3/algorithm/count_if.hpp>

  auto is_six = [](int i) -> bool { return i == 6; };
  std::vector<int> v{6, 2, 3, 4, 5, 6};
  auto c = ranges::count_if(v, is_six);
  std::cout << "vector:   " << c << '\n'; // 2

  std::array<int, 6> a{6, 2, 3, 4, 5, 6};
  c = ranges::count_if(a, is_six);
  std::cout << "array:    " << c << '\n'; // 2
}


// 计算 6出现的次数
TEST(rang_v3, count) {

  std::vector<int> v{6, 2, 3, 4, 5, 6};
  // note the count return is a numeric type
  // like int or long -- auto below make sure
  // it matches the implementation

  // 计数返回是一个数字类型
  auto c = ranges::count(v, 6);
  std::cout << "vector:   " << c << '\n';

  std::array<int, 6> a{6, 2, 3, 4, 5, 6};
  c = ranges::count(a, 6);
  std::cout << "array:    " << c << '\n';
}

// 类型转换
TEST(rang_v3, conversion) {
  // #include <range/v3/range/conversion.hpp>
  using namespace ranges;

  // repeat()方法返回一个新值，表示将原字符串重复n次
  // yield_from惰性求值
  auto vi = views::for_each(views::ints(1, 6),
							[](int i) { return yield_from(views::repeat_n(i, i)); }) |
	  to<std::vector>();
// prints: [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5]
  std::cout << views::all(vi) << '\n';
}

//
TEST(rang_v3, any_all_none_of) {

  auto is_six = [](int i) { return i == 6; };

  std::vector<int> v{6, 2, 3, 4, 5, 6};
  std:: cout << std::boolalpha;
  std:: cout << "vector: " << ranges::views::all(v) << '\n';

  // 任意的一个位是 6
  std:: cout << "vector any_of is_six: " << ranges::any_of(v, is_six) << '\n';

  // 全是6
  std::cout << "vector all_of is_six: " << ranges::all_of(v, is_six) << '\n';

  // 6没有
  std::cout << "vector none_of is_six: " << ranges::none_of(v, is_six) << '\n';
}


// 累计相加 从 0开始
TEST(rang_v3, accumulate_ints) {
  using namespace ranges;
  int sum = accumulate(views::ints(1, unreachable)
						   | views::transform([](int i) {
							 return i * i;
						   })
						   | views::take(10),
					   0);
  // prints: 385
  std::cout << sum << '\n';
}

//
TEST(rang_v3, grop_by) {
  std::vector<int> v2{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
  std::vector<std::pair<std::string, std::string>> v3{{"a", "a1"}, {"b", "b1"}, {"c", "c1"}};
  auto rng0 = ranges::views::group_by(v2, [](int i, int j) { return j - i < 3; });
  std::cout << rng0 << '\n';

  auto rng1 = v3 | ranges::views::group_by([](std::pair<std::string, std::string> &p0,
											  std::pair<std::string, std::string> &p1) {
	return p0.second == p1.second;
  });


/*  auto rng1 = v3 |ranges::views::group_by([](std::pair<std::string, std::string> &p0, std::pair<std::string, std::string> &p1) {return p0.second == p1.second;})
	  | ranges::views::transform([](std::pair<std::string, std::string> &a){
		cout << a.first << '\n';
		cout << a.second << '\n';
	  });*/
  //cout << rng1 << '\n';
}

TEST(rang_v3, split_when) {
  std::string str("now  is \t the\ttime");
  auto toks = ranges::actions::split_when(str, +[](int i) { return std::isspace(i); });
  std::stringstream stream;
  pprint::PrettyPrinter printer(stream);
  printer.compact(true);
  printer.print("toks = ", toks);
  for (const auto &item : toks) {
	LOG_DEBUG << item;
  }
}

template<typename F>
// NB: must be unconstrained
auto group_by_into_map(F &&f) {
  return ranges::views::transform([=](auto &&e) { return std::pair(std::invoke(f, e), e); })
	  | ranges::to<std::unordered_multimap>();

};


// 谓词分组
TEST(rang_v3, predicate_group) {

  struct Person {
	int Age;
	std::string Name;
  };

  std::vector<Person> persons{
	  {23, "Alice"},
	  {25, "Bob"},
	  {23, "Chad"}};

// group by .Age and put into std::map
  auto ageToPerson = persons
	  | ranges::views::transform([](const auto &person) {
		return std::pair{person.Age, person};
	  })
	  | ranges::to<std::map<int, Person>>();

  struct P { int a, b; };

  std::vector<P> v = {{1, 1}, {1, 2}, {2, 1}};

  std::stringstream stream;
  pprint::PrettyPrinter printer(stream);
  printer.compact(true);
  printer.print("toks = ", v);

  stream << &v;

  LOG_DEBUG << stream.str();

}




